package de.hauschild.gmltracer.gml.impl.value.geometry;

import java.util.ArrayList;
import java.util.List;

import de.hauschild.gmltracer.gml.Environment;
import de.hauschild.gmltracer.gml.Token;
import de.hauschild.gmltracer.gml.TokenStack;
import de.hauschild.gmltracer.gml.impl.AbstractToken;
import de.hauschild.gmltracer.gml.impl.array.ArrayToken;
import de.hauschild.gmltracer.gml.impl.value.StringToken;
import de.hauschild.gmltracer.gml.impl.value.integer.IntegerToken;
import de.hauschild.gmltracer.gml.impl.value.point.PointToken;
import de.hauschild.gmltracer.gml.impl.value.real.RealToken;
import de.hauschild.gmltracer.tracer.Light;
import de.hauschild.gmltracer.tracer.Renderer;
import de.hauschild.gmltracer.tracer.Shape;
import de.hauschild.gmltracer.tracer.impl.OnTheFlyRenderer;

public class RenderOperatorToken extends AbstractToken {

  private static final Renderer RENDERER = new OnTheFlyRenderer();

  @SuppressWarnings("unchecked")
  @Override
  public void evaluate(final Environment environment, final TokenStack tokenStack) {
    final StringToken fileName = tokenStack.pop(StringToken.class);
    final IntegerToken height = tokenStack.pop(IntegerToken.class);
    final IntegerToken width = tokenStack.pop(IntegerToken.class);
    final RealToken fov = tokenStack.pop(RealToken.class);
    final IntegerToken depth = tokenStack.pop(IntegerToken.class);
    final ShapeToken<? extends Shape> scene = tokenStack.pop(ShapeToken.class);
    final ArrayToken lights = tokenStack.pop(ArrayToken.class);
    final PointToken ambientLight = tokenStack.pop(PointToken.class);

    RENDERER.render(ambientLight.getValue(), convertLights(lights), scene.getValue(), depth.getValue(), fov.getValue(),
        width.getValue(), height.getValue(), fileName.getValue());
  }

  @Override
  public String toString() {
    return "render";
  }

  private List<Light> convertLights(final ArrayToken lights) {
    final List<Light> converted = new ArrayList<Light>();

    for (int i = 0; i < lights.getLength(); i++) {
      final Token lightToken = lights.get(i);
      if (lightToken instanceof LightToken) {
        converted.add(((LightToken) lightToken).getValue());
      } else {
        throw new IllegalArgumentException(String.format(
            "The light array for the 'render' command does not contains only lights. There was a %s.", lightToken));
      }
    }

    return converted;
  }
}
